//
//  MRClient.m
//  BonjourClient
//
//  Created by Magic on 12/8/11.
//  Copyright (c) 2011 __MyCompanyName__. All rights reserved.
//

#import "MRClient.h"
#import "GCDAsyncSocket.h"
#import "Event.h"
#import "MRAlertView.h"

#define kBigDataChunckSize 500

@implementation MRClient {
    NSNetServiceBrowser *_netServiceBrowser;
	NSNetService *_serverService;
	NSMutableArray *_serverAddresses;
	GCDAsyncSocket *_asyncSocket;
	BOOL _connected;
    
    NSMutableArray *_foundServices;
    
    
    NSMutableData *_bigData;
    NSUInteger chunckCount;
}


@synthesize delegate;
@synthesize connected = _connected;

+ (MRClient *)sharedClient
{
    static MRClient *sharedSingleton;
    static dispatch_once_t token;
    dispatch_once(&token, ^{
        sharedSingleton = [[MRClient alloc] init];
    });
    
    return sharedSingleton;
}

- (id)init {
    self = [super init];
    if (self) {
        _bigData = [[NSMutableData alloc] initWithCapacity:5000];
        
        _netServiceBrowser = [[NSNetServiceBrowser alloc] init];
        
        [_netServiceBrowser setDelegate:self];
        
        _foundServices = [[NSMutableArray alloc] initWithCapacity:5];
        
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
        
//        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
        
        
    }
    return self;
}


#pragma mark -- application notification --

- (void)applicationDidEnterBackground:(NSNotification *)notification
{
    [_netServiceBrowser stop];
}


#pragma mark -- private method --

- (void)searchForServicesOfType:(NSString *)type
{
    NSLog(@"searchForServicesOfType:%@",type);
    [_netServiceBrowser searchForServicesOfType:[NSString stringWithFormat:@"_%@._tcp.",type] inDomain:@"local."];
    
}

- (void)connectToReslovedAddress
{
	BOOL done = NO;
    
    
	int index = 0;
	while (!done && ([_serverAddresses count] > 0))
	{
		NSData *addr;
		
		// Note: The serverAddresses array probably contains both IPv4 and IPv6 addresses.
		// 
		// If your server is also using GCDAsyncSocket then you don't have to worry about it,
		// as the socket automatically handles both protocols for you transparently.
		
        
        addr = [_serverAddresses objectAtIndex:index];        
        
		
		NSLog(@"Attempting connection to %@", addr);
		
		NSError *err = nil;
		if ([_asyncSocket connectToAddress:addr error:&err])
		{
			done = YES;
		}
		else
		{
			NSLog(@"Unable to connect: %@", err);
		}
		
        //[_serverAddresses removeObjectAtIndex:index];
		index++;
	}
	
	if (!done)
	{
		NSLog(@"Unable to connect to any resolved address");
	}
}


- (BOOL)connectToServiceWithName:(NSString *)name
{
    for (NSNetService *service in _foundServices) 
    {
        if ([service.name isEqualToString:name]) 
        {
            [service setDelegate:self];
            [service resolveWithTimeout:5.0];
            
            /*
             NSInputStream *is;
             NSOutputStream *os;
             
             self.currentResolve = service;
             
             if ([service getInputStream:&is outputStream:&os]) {
             
             
             
             self.inputStream = is;
             self.outputStream = os;
             
             [is scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
             [os scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
             os.delegate = self;
             is.delegate = self;
             [is open];
             [os open];
             
             return YES;
             }*/
            
            return YES;
        }
    }
    
    return NO;
}

#pragma mark -- NetService callback --

- (void)netServiceBrowser:(NSNetServiceBrowser *)sender
           didFindService:(NSNetService *)netService
               moreComing:(BOOL)moreServicesComing
{
	NSLog(@"DidFindService: %@", [netService name]);
	
	
    if (!_serverService) {
        _serverService = netService;
    }
    [_foundServices addObject:netService];
    
    [[NSNotificationCenter defaultCenter] postNotificationName:@"MRServiceFound" object:nil userInfo:[NSDictionary dictionaryWithObject:netService.name forKey:@"ServiceName"]];    

    
    // Connect to the first service we find	

    if (!_connected) {
        [self connectToServiceWithName:[netService name]];
        
        [_netServiceBrowser stop];
    }
        
	
    
}

- (void)netServiceBrowser:(NSNetServiceBrowser *)sender
         didRemoveService:(NSNetService *)netService
               moreComing:(BOOL)moreServicesComing
{
	NSLog(@"DidRemoveService: %@", [netService name]);
    
    [_foundServices removeObject:netService];
    if ([_serverService isEqual:netService]) {
        _serverService = nil;
    }
    
    [[NSNotificationCenter defaultCenter] postNotificationName:@"MRServiceRemoved" object:nil userInfo:[NSDictionary dictionaryWithObject:netService.name forKey:@"ServiceName"]];
}

- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)sender
{
	NSLog(@"DidStopSearch");
    //[_netServiceBrowser stop];
    //[self performSelector:@selector(searchForServicesOfType:) withObject:@"mcremote" afterDelay:5];
}


- (void)netServiceDidResolveAddress:(NSNetService *)service
{
	NSLog(@"DidResolve: %@", [service name]);
	
	//if (_serverAddresses == nil)
	//{
		_serverAddresses = [[service addresses] mutableCopy];
	//}
	
	//if (_asyncSocket == nil)
	//{
		_asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
		
		
	//}
    
    [self connectToReslovedAddress];
}

- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict
{
	NSLog(@"DidNotResolve");
    
}

- (void)netServiceBrowser:(NSNetServiceBrowser *)sender didNotSearch:(NSDictionary *)errorInfo
{
	NSLog(@"DidNotSearch: %@", errorInfo);
    //    [_netServiceBrowser stop];
    //    [self performSelector:@selector(searchForServicesOfType:) withObject:@"mcremote" afterDelay:5];
}

#pragma mark -- AsyncSocket callback

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
	NSLog(@"Socket:DidConnectToHost: %@ Port: %hu", host, port);
	
	_connected = YES;
    
    [self.delegate didConnectToServer];
    
    [[NSNotificationCenter defaultCenter] postNotificationName:@"MRServiceConnected" object:nil userInfo:nil];
}

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
	NSLog(@"SocketDidDisconnect:WithError: %@", err);
    
    [[MRAlertView sharedAlertView] showWithTitle:NSLocalizedString(@"No Connection",@"")];
    
    _connected = NO;
    _serverService = nil;
    [_foundServices removeAllObjects];
    

    [self performSelector:@selector(searchForServicesOfType:) withObject:@"mcremote" afterDelay:1];
	
}

#pragma mark -- private method about socket

- (void)writeData:(NSData *)data tag:(NSInteger)tag
{
    if (!_connected)
	{
        NSLog(@"cannot write data");
        return;
    }
    [_asyncSocket writeData:data withTimeout:-1 tag:tag];
}

- (void)readDataToLength:(NSUInteger)length tag:(long)tag timeout:(NSTimeInterval)timeout
{
    if (timeout < 0) {
        [_asyncSocket readDataToLength:length withTimeout:timeout tag:tag];
    }
    else {
        [self readDataToLength:length tag:tag];
    }
}

- (void)readDataToLength:(NSUInteger)length tag:(long)tag
{    
//    if (length > kBigDataChunckSize) {
//        
//        NSUInteger got = 0;
//        while (1) {
//            chunckCount++;
//            if (got+kBigDataChunckSize < length) {
//                [_asyncSocket readDataToLength:kBigDataChunckSize withTimeout:5 tag:tag];
//                got+=kBigDataChunckSize;
//            }
//            else {
//                [_asyncSocket readDataToLength:length-got withTimeout:4 tag:tag];
//                break;
//            }
//        }
//    }
//    else {
        [_asyncSocket readDataToLength:length withTimeout:3 tag:tag];
//    }
    
}

#pragma mark -- AsyncSocket Callbacks --

- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
    
}

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
//    if (chunckCount > 0) {
//        chunckCount--;
//        [_bigData appendData:data];
//        if (chunckCount == 0) {
//            [self.delegate didReadData:_bigData withTag:tag];
//            [_bigData setLength:0];
//        }
//        //
//    }
//    else {
        [self.delegate didReadData:data withTag:tag];
//    }
}

- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag
                 elapsed:(NSTimeInterval)elapsed
               bytesDone:(NSUInteger)length
{
    NSLog(@"shoud timeout read");
    [self.delegate shouldTimeoutRead];
    return -1;
}

@end
